//
// Created by admin on 2022/2/25.
//

#ifndef PROJECT_CPP_THREAD_POOL_CPP_H
#define PROJECT_CPP_THREAD_POOL_CPP_H

#include <vector>
#include <queue>
#include <atomic>
#include <future>
#include <functional>

namespace ThreadPool {
#define DEFAULT_MAX_POOL_NUM 16

    //TODO 在内存占用过高时会出现大批任务在处理时或者join时出现0x0005错误
    /*class相比于struct是默认私有的封装（在正式确认第一个访问修饰符之前的成员变量）*/
    class SimplePool {
        using Task = std::function<void()>;// task任务别名
        std::vector<std::thread> _pool;// 线程池
        std::queue<Task> _tasks;// 任务队列
        std::mutex _lock; //同步锁
        std::condition_variable _taskCond; //条件阻塞
        std::atomic<bool> _isRun{true};// 线程池状态默认启动
        std::atomic<int> _freeCount{0};// 线程池中空闲数目


    public:
        explicit SimplePool(unsigned int count = std::thread::hardware_concurrency());/*定义初始化数目*/
        virtual ~SimplePool();


        /*提交*/
        /*
         常规写法
         * template<class F, class... Args>
        auto commit(F &&f, Args &&... args) -> std::future<decltype(f(args...))> {
         */
//        template<class F, class... Args, typename RetType = typename std::result_of<F(Args...)>::type>
//        std::future<RetType> commit(F &&f, Args &&... args) {
        template<class F, class... Args>
        auto commit(F &&f, Args &&... args) -> std::future<decltype(f(args...))> {
//            template<class F, class... Args>
//            auto commit(F &&f, Args &&... args) -> std::future<decltype(f(args...))> {
            if (!_isRun) {
                throw std::runtime_error("exception");
            }
            using RetType = decltype(f(args...));
            /*bind获取Task(匿名函数)*/
//            auto task = std::make_shared<std::packaged_task<RetType()>>(
//                    std::bind(std::forward<F>(f), std::forward<Args>(args)...)
//            );
            /*避免bind函数自动退化入参类型*/
            auto task = std::make_shared<std::packaged_task<RetType()>>(
                    std::bind(std::forward<F>(f), std::forward<Args>(args)...)
            );
            std::future<RetType> future = task->get_future();
            /*块锁*/
            {
                /*有效范围一个代码块*/
                std::lock_guard<std::mutex> lockGuard{_lock};
                /*切记这里一定要用拷贝外面的task，千万不可以引用，task引用周期仅限当前函数内部作用域*/
                /*同时这里使用的share指针，包装了package_task不仅减少内存分配，同时可以自动处理释放问题*/
                _tasks.push([task]() {
                    (*task)();
                });
            }
            /*唤醒一个线程用以执行*/
            _taskCond.notify_one();
            return future;

        }

        template<class F, class... Args>
        auto commit0(int count, F &&f, Args &&... args) -> std::future<decltype(f(args...))> {
            for (int i = 0; i < count; ++i) {
                commit(f, std::forward<Args>(args)...);
            }
        }

        /*获取空闲线程数*/
        int freeThreadCount() {
            return _freeCount;
        }

        /*获取线程数*/
        int poolSize() {
            return static_cast<int>(_pool.size());
        }

        /*添加线程数*/
        void addThread(unsigned int num);

        void shut();


    };
}


#endif //PROJECT_CPP_THREAD_POOL_CPP_H
